Skip to content

Conversation

@MananTank
Copy link
Member

@MananTank MananTank commented Aug 12, 2025


PR-Codex overview

This PR focuses on improving the UI components and functionality of the dashboard, including updates to country names, checkbox behavior, and form handling. It enhances user interactions and overall presentation in the settings and country selection areas.

Detailed summary

  • Updated DynamicHeight transition duration from 210ms to 250ms.
  • Enhanced Checkbox component to display MinusIcon for indeterminate state.
  • Corrected country names in utils.ts for consistency.
  • Added ChevronDownIcon and Button for tier expansion in country-selector.tsx.
  • Refactored tier selection logic and UI in country-selector.tsx.
  • Improved form structure and styling in index.tsx and related components.
  • Introduced FieldsetWithDescription for better layout in forms.
  • Added footer sections with save buttons in several fieldsets for clarity.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Checkbox now shows an indeterminate visual state.
    • Wallet settings sections get per-section Save buttons with loading spinners.
    • SMS country selector adds collapsible tier cards, partial-selection counters, and improved country tiles.
  • Refactor

    • Unified fieldset layouts with consistent headers, descriptions, dividers, and footers.
    • Branding settings reorganized into a responsive two-column layout.
    • Country tier rendering moved to modular TierCard components.
  • Bug Fixes

    • Corrected several country display names (e.g., South Korea, North Macedonia, Eswatini, Saint Lucia).
  • Style

    • Updated dynamic-height transition timing/easing.

@vercel vercel bot temporarily deployed to Preview – nebula August 12, 2025 16:21 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 12, 2025 16:21 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 12, 2025 16:21 Inactive
@vercel
Copy link

vercel bot commented Aug 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Project Deployment Preview Comments Updated (UTC)
thirdweb-www Ready Preview Comment Aug 12, 2025 9:49pm
4 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 ⬜️ Skipped Aug 12, 2025 9:49pm
nebula ⬜️ Skipped Aug 12, 2025 9:49pm
thirdweb_playground ⬜️ Skipped Aug 12, 2025 9:49pm
wallet-ui ⬜️ Skipped Aug 12, 2025 9:49pm

@vercel vercel bot temporarily deployed to Preview – docs-v2 August 12, 2025 16:21 Inactive
@linear
Copy link

linear bot commented Aug 12, 2025

@changeset-bot
Copy link

changeset-bot bot commented Aug 12, 2025

⚠️ No Changeset found

Latest commit: f7aa3e6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Aug 12, 2025
Copy link
Member Author


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@codecov
Copy link

codecov bot commented Aug 12, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.33%. Comparing base (827819b) to head (f7aa3e6).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7843   +/-   ##
=======================================
  Coverage   56.33%   56.33%           
=======================================
  Files         905      905           
  Lines       58834    58834           
  Branches     4158     4158           
=======================================
  Hits        33147    33147           
  Misses      25582    25582           
  Partials      105      105           
Flag Coverage Δ
packages 56.33% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@MananTank MananTank force-pushed the 08-12-_bld-80_dashboard_in-app_wallet_settings_page_ui_improvements branch from fe67520 to 0668018 Compare August 12, 2025 16:23
@vercel vercel bot temporarily deployed to Preview – nebula August 12, 2025 16:23 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 12, 2025 16:23 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 12, 2025 16:23 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 12, 2025 16:23 Inactive
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 12, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds per-section save buttons with isUpdating wiring and reusable Fieldset primitives to in-app wallet settings; refactors Branding layout; introduces a collapsible TierCard-based SMS country selector and updates several country display names; adds tri-state Checkbox rendering and tweaks DynamicHeight transition timing.

Changes

Cohort / File(s) Summary
Checkbox tri-state
apps/dashboard/src/@/components/ui/checkbox.tsx
Render a MinusIcon when checked === "indeterminate", otherwise render CheckIcon; no public API changes.
In-app wallet settings refactor
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
Replace top-level layout with Fieldset/FieldsetWithDescription primitives, add per-section Save buttons and isUpdating wiring, reorganize Branding (two-column grid, Application Name, AppImageFormControl), and update component props to accept isUpdating, embeddedWalletService, and client.
SMS country selector UX overhaul
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx
Introduce TierCard with collapsible bodies, header checkbox supporting indeterminate state, per-country Button tiles with CheckIcon, revised selection logic and responsive grid layout; public API unchanged.
Country name updates
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts
Update display names for codes KN, KR, LC, MK, PM, RE, SZ, VC; no structural/type changes.
DynamicHeight transition tweak
apps/dashboard/src/@/components/ui/DynamicHeight.tsx
Change default transition from "height 210ms cubic-bezier(...)" to "height 250ms ease" (single-line conditional); behavior otherwise unchanged.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant UI as InAppWalletSettingsUI
  participant FS as Fieldset (section)
  participant API as update handler
  User->>FS: Edit fields in section
  User->>FS: Click "Save" (section)
  FS->>UI: invoke section save (sets isUpdating=true)
  UI->>API: perform update (e.g., updateApiKey / embeddedWalletService)
  API-->>UI: return success/failure
  UI-->>FS: set isUpdating=false
Loading
sequenceDiagram
  actor User
  participant CS as CountrySelector
  participant TC as TierCard
  participant Parent as Parent Form
  User->>TC: Toggle tier checkbox / click country tile
  TC->>CS: onTierToggle / onToggleCountry
  CS->>Parent: onChange(selectedCountries)
  Note over TC,CS: Header checkbox reflects indeterminate when partially selected
  User->>TC: Click expand/collapse
  TC-->>User: Show/hide tier body
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Assessment against linked issues

Objective Addressed Explanation
Add per-section Save buttons to in-app wallet settings so users don’t have to scroll past SMS countries to save (BLD-80)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Add tri-state indicator to Checkbox (apps/dashboard/src/@/components/ui/checkbox.tsx) UI component enhancement unrelated to BLD-80's per-section save button objective.
SMS country selector UX overhaul (.../sms-country-select/country-selector.tsx) Large UX refactor (TierCard, collapsible tiers, per-country tiles) beyond the single objective of moving save buttons.
Update country display names (.../sms-country-select/utils.ts) Data label corrections unrelated to the save-button placement objective.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 08-12-_bld-80_dashboard_in-app_wallet_settings_page_ui_improvements

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 12, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.06 KB (0%) 1.3 s (0%) 198 ms (+137.3% 🔺) 1.5 s
thirdweb (cjs) 357.05 KB (0%) 7.2 s (0%) 699 ms (+15.53% 🔺) 7.9 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 73 ms (+1565.8% 🔺) 187 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 51 ms (+2528.18% 🔺) 62 ms
thirdweb/react (minimal + tree-shaking) 19.15 KB (0%) 383 ms (0%) 76 ms (+508.02% 🔺) 459 ms

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx (1)

160-171: Consider adding keyboard navigation support for the expand/collapse button.

While the Button component likely handles basic keyboard interactions, consider adding an aria-expanded attribute to improve accessibility for screen reader users.

           <Button
             variant="ghost"
             className="p-0 size-7"
             onClick={() => setIsExpanded(!isExpanded)}
+            aria-expanded={isExpanded}
+            aria-label={isExpanded ? "Collapse tier" : "Expand tier"}
           >
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (1)

349-367: Consider adding validation for the Application Name field.

While the field defaults to the API Key's name when empty, consider adding client-side validation to ensure the name meets any length or character requirements.

               <FormControl>
                 <Input {...field} />
               </FormControl>
+              <FormDescription>
+                Name that will be displayed in the emails sent to users.{" "}
+                <br className="max-sm:hidden" /> Defaults to your API Key's
+                name. Maximum 50 characters.
+              </FormDescription>
               <FormMessage />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8665e8f and 0668018.

📒 Files selected for processing (4)
  • apps/dashboard/src/@/components/ui/checkbox.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (7 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/@/components/ui/checkbox.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/@/components/ui/checkbox.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/@/components/ui/checkbox.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
🧠 Learnings (5)
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
PR: thirdweb-dev/js#7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/dashboard/src/@/components/ui/checkbox.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Icons come from `lucide-react` or the project-specific `…/icons` exports – never embed raw SVG.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
🧬 Code Graph Analysis (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx (3)
apps/dashboard/src/@/components/ui/checkbox.tsx (1)
  • Checkbox (34-34)
apps/playground-web/src/lib/utils.ts (1)
  • cn (5-7)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts (4)
  • tierPricing (2-8)
  • countryNames (11-232)
  • getCountryFlag (458-465)
  • countryPrefixes (234-455)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (3)
packages/thirdweb/src/react/web/ui/components/Spinner.tsx (1)
  • Spinner (11-34)
apps/dashboard/src/@/components/ui/input.tsx (1)
  • Input (25-25)
apps/playground-web/src/lib/utils.ts (1)
  • cn (5-7)
🔇 Additional comments (8)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts (1)

120-220: LGTM! Country name updates are accurate and improve consistency.

The updates to country display names align with internationally recognized standards:

  • Saint names are now fully spelled out (e.g., "St Kitts" → "Saint Kitts")
  • Political names reflect current realities (e.g., "Macedonia" → "North Macedonia", "Swaziland" → "Eswatini")
  • Corrections for accuracy (e.g., "Korea Republic of" → "South Korea", "Reunion/Mayotte" → "Réunion")
apps/dashboard/src/@/components/ui/checkbox.tsx (1)

24-28: LGTM! Well-implemented tri-state checkbox support.

The implementation correctly handles the indeterminate state using the standard checked === "indeterminate" pattern. The icons are appropriately sized for visual consistency.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx (3)

75-96: LGTM! Clean component decomposition with TierCard extraction.

The refactoring to extract TierCard as a separate component improves modularity and readability. The data flow is clean with appropriate props passed down.


115-118: Good UX choice for partial selection indicators.

The tri-state checkbox with indeterminate state for partial selections, combined with the counter display, provides clear visual feedback to users about the selection state of each tier.


185-208: LGTM! Clean country selection UI with good visual hierarchy.

The Button-based country tiles with flag, name, and prefix provide excellent visual feedback and accessibility. The CheckIcon for selected states is well-positioned.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (3)

243-296: Well-structured form with clear section separation.

The refactoring to use Fieldset components with per-section Save buttons successfully addresses the PR objective of not requiring users to scroll past long country lists to save top-level settings. Each section now has its own save action, improving the user experience.


308-319: Clean implementation of per-section save with loading states.

The footer with Save button and loading spinner provides good user feedback during updates. The consistent pattern across all sections (Branding, Native Apps, Authentication) ensures a uniform experience.


817-837: Well-designed reusable Fieldset components.

The Fieldset and FieldsetWithDescription components provide a consistent structure for form sections with proper semantic HTML, dynamic height animations, and flexible footer support. This promotes maintainability and consistency across the form.

@MananTank MananTank force-pushed the 08-12-_bld-80_dashboard_in-app_wallet_settings_page_ui_improvements branch from 0668018 to e6f10f9 Compare August 12, 2025 21:17
@vercel vercel bot temporarily deployed to Preview – nebula August 12, 2025 21:17 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 12, 2025 21:17 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 12, 2025 21:17 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 12, 2025 21:17 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (4)

260-269: Disable the section Save button when not dirty or while updating

Prevents accidental double submits and clarifies state. You already show a spinner; disabling completes the UX.

Apply this diff:

               <Button
                 className="gap-2"
                 type="submit"
                 size="sm"
                 variant="outline"
+                disabled={props.isUpdating || !form.formState.isDirty}
               >
                 {props.isUpdating && <Spinner className="size-4" />}
                 Save
               </Button>

315-322: Disable Branding section Save while updating or when no changes

Same rationale as Authentication; avoids redundant submissions.

-          <Button className="gap-2" type="submit" size="sm" variant="outline">
+          <Button
+            className="gap-2"
+            type="submit"
+            size="sm"
+            variant="outline"
+            disabled={props.isUpdating || !props.form.formState.isDirty}
+          >

769-773: Disable Native Apps Save while updating or when no changes

Keeps section Save behavior consistent.

-          <Button className="gap-2" type="submit" size="sm" variant="outline">
+          <Button
+            className="gap-2"
+            type="submit"
+            size="sm"
+            variant="outline"
+            disabled={props.isUpdating || !form.formState.isDirty}
+          >

95-104: trackingData is computed but not consumed by update path

InAppWalletSettingsUI requires updateApiKey(projectValues, trackingData) and you compute tracking booleans at Lines 233-236, but the upstream implementation (handleUpdateProject) ignores the second arg. Either wire this into analytics/telemetry or drop the parameter to avoid dead code.

If you intend to remove it for now, adjust the type and call site:

-const InAppWalletSettingsPageUI: React.FC<
-  InAppWalletSettingsPageProps & {
-    updateApiKey: (
-      projectValues: Partial<Project>,
-      trackingData: UpdateAPIKeyTrackingData,
-    ) => void;
+const InAppWalletSettingsPageUI: React.FC<
+  InAppWalletSettingsPageProps & {
+    updateApiKey: (projectValues: Partial<Project>) => void;
-export const InAppWalletSettingsUI: React.FC<
+export const InAppWalletSettingsUI: React.FC<
   InAppWalletSettingsPageProps & {
-    updateApiKey: (
-      projectValues: Partial<Project>,
-      trackingData: UpdateAPIKeyTrackingData,
-    ) => void;
+    updateApiKey: (projectValues: Partial<Project>) => void;
-  props.updateApiKey(
-      {
-        services: newServices,
-      },
-      {
-        hasCustomAuthEndpoint: !!customAuthEndpoint,
-        hasCustomBranding: !!branding,
-        hasCustomJwt: !!customAuthentication,
-      },
-    );
+  props.updateApiKey({
+    services: newServices,
+  });

Alternatively, if you plan to track, I can help add a lightweight telemetry hook that consumes these flags.

Also applies to: 228-237

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0668018 and e6f10f9.

📒 Files selected for processing (5)
  • apps/dashboard/src/@/components/ui/DynamicHeight.tsx (1 hunks)
  • apps/dashboard/src/@/components/ui/checkbox.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (9 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx
  • apps/dashboard/src/@/components/ui/checkbox.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/@/components/ui/DynamicHeight.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/@/components/ui/DynamicHeight.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/@/components/ui/DynamicHeight.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
🧠 Learnings (5)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Spacing utilities (`px-*`, `py-*`, `gap-*`) are preferred over custom margins.

Applied to files:

  • apps/dashboard/src/@/components/ui/DynamicHeight.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use the `container` class with a `max-w-7xl` cap for page width consistency.

Applied to files:

  • apps/dashboard/src/@/components/ui/DynamicHeight.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Use React Query (`tanstack/react-query`) for all client data fetching.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
🧬 Code Graph Analysis (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (4)
packages/thirdweb/src/react/web/ui/components/Spinner.tsx (1)
  • Spinner (11-34)
apps/portal/src/components/ui/underline-link.tsx (1)
  • UnderlineLink (6-16)
apps/playground-web/src/lib/utils.ts (1)
  • cn (5-7)
apps/dashboard/src/@/components/ui/DynamicHeight.tsx (1)
  • DynamicHeight (7-33)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (5)

242-254: Per-section Save UI and spacing look good

Moving to a stacked form layout with section footers aligns with the issue objective and improves discoverability of Save actions. No concerns here.


535-541: LGTM: UnderlineLink usage

Good move to standardized UnderlineLink with proper noopener/noreferrer for external links.


625-632: LGTM: Link consistency

Same as above; consistent UX for documentation links.


439-455: Image upload UX is resilient

Good error handling and optimistic state reset on failure; overlay spinner feedback is clear.

Also applies to: 456-461


818-824: Fade-in-0 Animation Utility Verified

I confirmed that the tailwindcss-animate plugin is enabled (with an empty prefix) in each app’s tailwind.config.{js,ts}, so the fade-in-0 and animate-in classes are valid and will produce the expected entrance animation. No changes needed here.

@graphite-app
Copy link
Contributor

graphite-app bot commented Aug 12, 2025

Merge activity

<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the UI components and improving the country selection functionality in the dashboard application. It includes updates to transitions, checkbox indicators, and country names for better clarity and usability.

### Detailed summary
- Updated transition duration in `DynamicHeight.tsx`.
- Added `MinusIcon` for indeterminate state in `checkbox.tsx`.
- Corrected country names in `utils.ts` for several countries.
- Improved structure and styling of the `CountrySelector` component.
- Added `ChevronDownIcon` and `Button` for toggling tiers in `country-selector.tsx`.
- Refactored `Fieldset` and `FieldsetWithDescription` components for better layout and usability in settings forms.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- New Features
  - Checkbox now supports an indeterminate state with a clear visual indicator.
  - Wallet settings sections gain per-section Save buttons with loading spinners.
  - SMS country selection adds collapsible tier cards, partial-selection counters, and improved country tiles with clear selection states.

- Refactor
  - Unified fieldset layouts with consistent headers, descriptions, dividers, and footers.
  - Branding settings reorganized into a responsive two‑column layout with improved flow.
  - Country tier rendering moved to modular TierCard components.

- Bug Fixes
  - Corrected several country display names (e.g., South Korea, North Macedonia, Eswatini, Saint Lucia).

- Style
  - Adjusted a height-transition timing/easing for dynamic-height animations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@graphite-app graphite-app bot force-pushed the 08-12-_bld-80_dashboard_in-app_wallet_settings_page_ui_improvements branch from e6f10f9 to f7aa3e6 Compare August 12, 2025 21:41
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 12, 2025 21:41 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 12, 2025 21:41 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula August 12, 2025 21:41 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 12, 2025 21:41 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (1)

705-729: Buttons may submit the form unintentionally; set type="button"

Inside a form, a button without an explicit type defaults to submit. The “Remove header” and “Add header” buttons should not submit the form.

-                <Button
+                <Button
+                  type="button"
                   aria-label="Remove header"
                   className="!w-auto px-3"
                   onClick={() => {
                     customHeaderFields.remove(customHeaderIdx);
                   }}
                   variant="outline"
                 >
@@
-          <Button
+          <Button
+            type="button"
             className="w-full gap-2 bg-background"
             onClick={() => {
               customHeaderFields.append({
                 key: "",
                 value: "",
               });
             }}
             variant="outline"
           >

Also applies to: 734-746

♻️ Duplicate comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (2)

827-846: A11y: must be the first child of

(do not wrap it in a div)

The current markup nests legend inside a div. This is invalid HTML and harms semantics for assistive tech. Make legend the first child and place actions/headers alongside without wrapping legend.

-function Fieldset(props: {
-  legend: string;
-  children: React.ReactNode;
-  footer?: React.ReactNode;
-}) {
-  return (
-    <div className="rounded-lg border bg-card relative">
-      <DynamicHeight>
-        <fieldset className="p-4 md:px-6 md:py-5">
-          {/* put inside div to remove default styles on legend  */}
-          <div className="border-b pb-4 mb-5 border-dashed font-semibold text-xl tracking-tight">
-            <legend> {props.legend}</legend>
-          </div>
-
-          {props.children}
-        </fieldset>
-      </DynamicHeight>
-      {props.footer}
-    </div>
-  );
-}
+function Fieldset(props: {
+  legend: string;
+  children: React.ReactNode;
+  footer?: React.ReactNode;
+  headerActions?: React.ReactNode; // new, for top-right Save, etc.
+}) {
+  return (
+    <div className="relative rounded-lg border bg-card">
+      <DynamicHeight>
+        <fieldset className="p-4 md:px-6 md:py-5">
+          <legend className="mb-5 border-b border-dashed pb-4 font-semibold text-xl tracking-tight">
+            {props.legend}
+          </legend>
+          {props.headerActions ? (
+            <div className="absolute right-6 top-4">{props.headerActions}</div>
+          ) : null}
+          {props.children}
+        </fieldset>
+      </DynamicHeight>
+      {props.footer}
+    </div>
+  );
+}

849-873: A11y: must be direct child of

(same issue in FieldsetWithDescription)

Move legend to be the first child of fieldset; place the description after it. This mirrors the fix above.

-function FieldsetWithDescription(props: {
-  legend: string;
-  children: React.ReactNode;
-  footer?: React.ReactNode;
-  description: React.ReactNode;
-}) {
-  return (
-    <div className="rounded-lg border bg-card relative">
-      <DynamicHeight>
-        <fieldset className="p-4 md:p-6">
-          {/* put inside div to remove default styles on legend  */}
-          <div className="pr-20">
-            <legend className="font-semibold text-xl tracking-tight">
-              {props.legend}
-            </legend>
-            <p className="text-muted-foreground text-sm">{props.description}</p>
-          </div>
-
-          {props.children}
-        </fieldset>
-      </DynamicHeight>
-      {props.footer}
-    </div>
-  );
-}
+function FieldsetWithDescription(props: {
+  legend: string;
+  children: React.ReactNode;
+  footer?: React.ReactNode;
+  description: React.ReactNode;
+}) {
+  return (
+    <div className="relative rounded-lg border bg-card">
+      <DynamicHeight>
+        <fieldset className="p-4 md:p-6">
+          <legend className="pr-20 font-semibold text-xl tracking-tight">
+            {props.legend}
+          </legend>
+          <div className="pr-20">
+            <p className="text-muted-foreground text-sm">{props.description}</p>
+          </div>
+          {props.children}
+        </fieldset>
+      </DynamicHeight>
+      {props.footer}
+    </div>
+  );
+}
🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (2)

312-323: Branding footer Save is fine, but consider consistent header placement

This section likely won’t overflow, so footer is acceptable. For consistency and to avoid later regressions if content grows, you may consider headerActions here too (optional).


353-385: Place FormMessage after the control for better a11y and UX

FormMessage appears above the input inside the header block. Validation messages should follow the control they describe.

               <FormItem className="lg:border-r lg:border-dashed lg:pr-6">
                 <div className="space-y-1">
                   <FormLabel>Application Image URL</FormLabel>
                   <FormDescription className="!mb-4">
                     Logo that will display in the emails sent to users.{" "}
                     <br className="max-sm:hidden" /> The image must be squared
                     with recommended size of 72x72 px.
                   </FormDescription>
-
-                  <FormMessage />
                 </div>

                 <FormControl>
                   <AppImageFormControl
                     client={props.client}
                     setUri={(uri) => {
                       props.form.setValue("branding.applicationImageUrl", uri, {
                         shouldDirty: true,
                         shouldTouch: true,
                       });
                     }}
                     uri={props.form.watch("branding.applicationImageUrl")}
                   />
                 </FormControl>
+                <FormMessage />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e6f10f9 and f7aa3e6.

📒 Files selected for processing (5)
  • apps/dashboard/src/@/components/ui/DynamicHeight.tsx (1 hunks)
  • apps/dashboard/src/@/components/ui/checkbox.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (9 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/dashboard/src/@/components/ui/checkbox.tsx
  • apps/dashboard/src/@/components/ui/DynamicHeight.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/utils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/sms-country-select/country-selector.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
🧠 Learnings (4)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Use React Query (`tanstack/react-query`) for all client data fetching.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx
🧬 Code Graph Analysis (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (5)
packages/thirdweb/src/react/web/ui/components/Spinner.tsx (1)
  • Spinner (11-34)
apps/dashboard/src/@/components/ui/input.tsx (1)
  • Input (25-25)
apps/portal/src/components/ui/underline-link.tsx (1)
  • UnderlineLink (6-16)
apps/playground-web/src/lib/utils.ts (1)
  • cn (5-7)
apps/dashboard/src/@/components/ui/DynamicHeight.tsx (1)
  • DynamicHeight (7-33)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Lint Packages
  • GitHub Check: Unit Tests
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/settings/components/index.tsx (6)

242-242: LGTM: form stack spacing

Switching to space-y-6 is consistent with the rest of the dashboard and improves readability.


250-254: Per-section isUpdating wiring looks good

Passing isUpdating into Branding and Native Apps fieldsets enables per-section spinners as intended.


818-825: LGTM: Controlled reveal container

The gated container reveals with a short entry animation and respects plan gating. Looks good.


256-271: AI summary discrepancy: only one Save for Authentication (not per-subsection)

The AI summary states per-section Save buttons in Authentication. In this file, there is a single Save for the entire Authentication fieldset, not separate Saves for JWT, Custom Auth Endpoint, and SMS. See lines 256-271 (one footer/button) and the subsections at 535-541 and 626-632 with no separate Save controls.

Consider splitting Authentication into three fieldsets (JWT, Custom Endpoint, SMS) each with its own headerActions Save, or keep a single fieldset but move Save to the header as suggested above to avoid scrolling issues with the SMS list. Do you want me to draft that refactor?

Also applies to: 535-541, 626-632


759-775: Native Apps footer Save looks good

Consistent with the pattern; spinner integration matches the Branding section.


266-266: Spinner API Usage Is Correct
The Spinner component imported from @/components/ui/Spinner/Spinner.tsx defines its props as { className?: string } and applies "size-4" as the default when no className is provided. Therefore, using <Spinner className="size-4" /> (and similarly elsewhere) aligns with its API and requires no changes.

Likely an incorrect or invalid review comment.

Comment on lines +256 to +271
<Fieldset
legend="Authentication"
footer={
<div className="flex justify-end p-4 md:px-6 border-t border-dashed">
<Button
className="gap-2"
type="submit"
size="sm"
variant="outline"
>
{props.isUpdating && <Spinner className="size-4" />}
Save
</Button>
</div>
}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Save button for Authentication is still below the long SMS list; move actions to the header

The Save button is in the Fieldset footer, which will still be below the entire Authentication section and buried under the long SMS country list. This doesn’t satisfy BLD-80’s objective to avoid excessive scrolling for Save.

Recommend moving the Save action into the Fieldset header (top-right), so it’s always at the top of this section. Suggest also fixing semantics at the same time in the Fieldset component.

Apply this diff here to pass actions to the header instead of the footer:

-        <Fieldset
-          legend="Authentication"
-          footer={
-            <div className="flex justify-end p-4 md:px-6 border-t border-dashed">
-              <Button
-                className="gap-2"
-                type="submit"
-                size="sm"
-                variant="outline"
-              >
-                {props.isUpdating && <Spinner className="size-4" />}
-                Save
-              </Button>
-            </div>
-          }
-        >
+        <Fieldset
+          legend="Authentication"
+          headerActions={
+            <Button className="gap-2" type="submit" size="sm" variant="outline">
+              {/* NOTE: see Spinner API verification comment below */}
+              {props.isUpdating && <Spinner className="size-4" />}
+              Save
+            </Button>
+          }
+        >

And update the Fieldset component to support headerActions and proper legend semantics (see a11y comment below for the component-level diff).

Committable suggestion skipped: line range outside the PR's diff.

@graphite-app graphite-app bot merged commit f7aa3e6 into main Aug 12, 2025
24 checks passed
@graphite-app graphite-app bot deleted the 08-12-_bld-80_dashboard_in-app_wallet_settings_page_ui_improvements branch August 12, 2025 21:50
@vercel vercel bot temporarily deployed to Production – nebula August 12, 2025 21:50 Inactive
@vercel vercel bot temporarily deployed to Production – docs-v2 August 12, 2025 21:50 Inactive
@vercel vercel bot temporarily deployed to Production – wallet-ui August 12, 2025 21:50 Inactive
@vercel vercel bot temporarily deployed to Production – thirdweb_playground August 12, 2025 21:50 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants